package com.xyf.sys.util;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author vnjohn
 * @since 2023/2/19
 */
public class SignUtil {
    /**
     * 这里是自定义 Token，需和你在公众号后台提交的 Token 保持一致
     */
    private static final String TOKEN = "Tokenxxxx";

    /**
     * 校验签名
     *
     * @param signature 签名
     * @param timestamp 时间戳
     * @param nonce     随机数
     * @return 布尔值
     */
    public static boolean checkSignature(String token ,String signature, String timestamp, String nonce) {
        String checktext = null;
        if (null != signature) {
            // 对ToKen,timestamp,nonce 按字典排序
            String[] paramArr = new String[]{token, timestamp, nonce};
            Arrays.sort(paramArr);
            // 将排序后的结果拼成一个字符串
            String content = paramArr[0].concat(paramArr[1]).concat(paramArr[2]);

            try {
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                // 对接后的字符串进行sha1加密
                byte[] digest = md.digest(content.getBytes());
                checktext = byteToStr(digest);
            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        // 将加密后的字符串与signature进行对比
        return checktext != null && checktext.equals(signature.toUpperCase());
    }

    /**
     * 将字节数组转化为16进制字符串
     *
     * @param byteArrays 字符数组
     * @return 字符串
     */
    private static String byteToStr(byte[] byteArrays) {
        String str = "";
        for (int i = 0; i < byteArrays.length; i++) {
            str += byteToHexStr(byteArrays[i]);
        }
        return str;
    }

    /**
     * 将字节转化为十六进制字符串
     *
     * @param myByte 字节
     * @return 字符串
     */
    private static String byteToHexStr(byte myByte) {
        char[] Digit = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
        char[] tampArr = new char[2];
        tampArr[0] = Digit[(myByte >>> 4) & 0X0F];
        tampArr[1] = Digit[myByte & 0X0F];
        String str = new String(tampArr);
        return str;
    }

    public static String toUtf8(String value) throws Exception {
        return java.net.URLEncoder.encode(value, "UTF-8");
    }

    public static String specialUrlEncode(String value) throws Exception {
        return value.replace("+", "%20").replace("*", "%2A").replace("%7E", "~");
    }

//    public static String getSignature(String data, String key) throws Exception {
//        byte[] keyBytes = key.getBytes();
//
//        SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
//
//        Mac mac = Mac.getInstance("HmacSHA1");
//
//        mac.init(signingKey);
//
//        byte[] rawHmac = mac.doFinal(data.getBytes());
//
//        String hexBytes = byte2hex(rawHmac);
//
//        return new sun.misc.BASE64Encoder().encode(hexBytes.getBytes());
//    }

    private static String byte2hex(final byte[] b) {
        String hs = "";

        String stmp = "";

        for (int n = 0; n < b.length; n++) {

            stmp = (Integer.toHexString(b[n] & 0xFF));

            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;

            } else {
                hs = hs + stmp;

            }

        }

        return hs;

    }

    /**
     * Java实现PHP中的http_build_query()效果
     *
     * @param array key=value形式的二位数组
     * @return
     */
    public static String http_build_query(Map<String, String> array) {
        String reString = null;
        //遍历数组形成akey=avalue&bkey=bvalue&ckey=cvalue形式的的字符串
        Iterator it = array.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, String> entry = (Map.Entry) it.next();
            String key = entry.getKey();
            String value = entry.getValue();
            reString += key + "=" + value + "&";
        }
        reString = reString.substring(0, reString.length() - 1);
        //将得到的字符串进行处理得到目标格式的字符串
        try {
            reString = java.net.URLEncoder.encode(reString, "utf-8");
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        reString = reString.replace("%3D", "=").replace("%26", "&");

        // 去除第一个多余的null符号
        return reString.substring(4);

    }

    public static String getSignStr(Map<String, String> params, String secret) {
        // 字母顺序排序后拼接签名串
        String signStr = params.keySet().stream()
                .sorted()
                .map(key -> key + "=" + params.get(key))
                .collect(Collectors.joining("&"));
        // 生成 HMAC 签名
        Mac mac = null;
        try {
            mac = Mac.getInstance("HmacSHA256");
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        SecretKeySpec secretKeySpec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        try {
            mac.init(secretKeySpec);
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        byte[] hmacBytes = mac.doFinal(signStr.getBytes(StandardCharsets.UTF_8));
        // 将字节转换为十六进制字符串
        StringBuilder sign = new StringBuilder();
        for (byte b : hmacBytes) {
            sign.append(String.format("%02x", b));
        }
        return sign.toString();
    }

}
